﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace 魔数
{
    public partial class Form1 : Form
    {
        static int N = 12;
        int[] b = new int[N + 1];  //用于标记1-N这些数字是否已经被使用（方格填数问题）
        int[] a = new int[10];    //方格填数问题
        //checkMatrix矩阵用于方格填数问题，{5,7,-1}表示所填的数要与5、7两个位置的数比较
        //{-1,-1,-1}表示不需要与任何数比较
        int[,] checkMatrix = { { -1, -1, -1 }, { 0, -1, -1 }, { 1, -1, -1 }, 
                                   { 0, -1, -1 }, {1,3,-1},{2,4,-1},
                                   {3,-1,-1},{4,6,-1},{5,7,-1}};

        int[] deltai = { 2, 1, -1, -2, -2, -1, 1, 2 };  //用于马的遍历问题
        int[] deltaj = { 1,2,2,1,-1,-2,-2,-1 };         //用于马的遍历问题
        int[,] board = new int[8, 8];                   //用于马的遍历问题，标记棋盘各坐标是否已用


        public Form1()
        {
            InitializeComponent();
        }

        private int [] GetNext(string pstr)  //获取模式串的next数组
        {
            int len=pstr.Length;        //模式串的长度
            
            string[] arr=new string[len];   //模式串各字符数组

            int[] next = new int[len+1];   //next函数数组，多取一位避免while循环时溢出

            for (int k = 0; k < len; k++)
            {
                arr[k] = pstr.Substring(k,1);  //模式串字符数组赋值
            }

            next[0] = -1;  //赋初始值
            int j = -1;
            int i = 0;

            while (i < len)
            {
                if (j == -1 || arr[i] == arr[j]) { ++i; ++j; next[i] = j; }  //字符串第i字符和第i-1字符相同，i、j都加1
                else j = next[j];   //否则重新设置j的开始值
            }

            for (int k = 0; k < arr.Length; k++)  //显示模式串及其next函数值
            {
                if (k == 0) { label1.Text = "原字符串："; label2.Text = "next函数值："; }
                label1.Text += arr[k];
                label2.Text += next[k].ToString()+"、";
            }
            return next;
        }

        private void button2_Click(object sender, EventArgs e)  //主串与模式串比较
        {
            string mstr = textBox2.Text;  //主串
            int mlen = mstr.Length;       //主串长度
            string[] marr = new string[mlen];  //主串字符数组
            for (int k = 0; k < mlen; k++)      //主串数组赋值
            {
                marr[k] = mstr.Substring(k,1);  //把字符串中的字符逐个分解至数组中
            }

            int[] next = GetNext(textBox1.Text);  //获得next函数值

            string pstr=textBox1.Text;  //获得输入的模式串
            int plen = pstr.Length;     //模式串的长度
            string [] parr=new string[plen]; //模式串字符数组 

            for (int k = 0; k < plen; k++)      //模式串数组赋值
            {
                parr[k] = pstr.Substring(k,1);
            }          

            int i = -1;
            int j = -1;
            while (i < mlen && j < plen)
            {
                if (j == -1 || marr[i] == parr[j]) { ++i; ++j; }
                else { j = next[j]; }
            }
            if (j >= plen) label5.Text = "模式串存在，位于" + (i - plen).ToString();   //i-plen是模式串位于主串的位置（起始位置）
            else label5.Text = "模式串不存在！";
        }

        private void button3_Click(object sender, EventArgs e)//迭代二分查找法求方程的根
        {
            double i = this.mycuba(0.00001, 1.0, 2.0);
            MessageBox.Show(i.ToString(), "j=", MessageBoxButtons.OK);
        }
        private double mycuba(double f, double a, double b) //二分查找法解方程
        {
            double i = a + (b - a) / 2;
            while (System.Math.Abs(i * i * i-5) > f)
            {
                if (i * i * i - 5 > 0)
                {
                    b =a+ (b - a) / 2;
                }
                else
                {
                    a = a+ (b - a) / 2;
                }
                i = a + (b - a) / 2;
               // MessageBox.Show(i.ToString(), "i=", MessageBoxButtons.OK);
            }
            return i;
        }

        private void merge(int [] A,int p, int q, int r) //分治法归并排序的归并
        {
            //pa(a,"a");
            MessageBox.Show("P="+p.ToString()+",Q="+q.ToString()+",R="+r.ToString(),"合并", MessageBoxButtons.OK);
            pa(A, "A数列的值");
            int n1 = q - p + 1;
            int n2 = r - q;
            int i, j, k;
            int[] L = new int[50];
            int[] R = new int[50];
            for (i = 0; i < n1; i++)
            {
                L[i] = A[p+i];
            }
            
            for (i = 0; i < n2; i++)
            {
                //MessageBox.Show(i.ToString(), "右侧i值", MessageBoxButtons.OK);
                R[i] = A[q +1+ i];
            }
            //MessageBox.Show(n1.ToString(), "n1值", MessageBoxButtons.OK);
            L[n1] = 100;
            
            R[n2] = 100;
           // pa(L, "左侧");

            i = 0;
            j = 0;
            //pa(R, "右侧");

            for (k = p; k < r + 1; k++)
            {
                if (L[i] < R[j])
                {
                    A[k] = L[i];
                    i++;
                }
                else
                {
                    A[k] = R[j];
                    j++;
                }               
            }
            //pa(a, "归并后的a");
        }
        private void mergesort(int[] A, int p, int r)  //分治法归并排序
        {
            int q;
            
            if (p < r)
            {
                q = (p + r) / 2;
               // MessageBox.Show("p="+p.ToString(), "排序中的q="+q.ToString(), MessageBoxButtons.OK);
                mergesort(A, p, q);//排序前半
                mergesort(A, q+1, r); //排序后半
                merge(A, p, q, r); //两半归并
            }
            
        }

        private void button4_Click(object sender, EventArgs e)  //分治排序主程序
        {
            int [] a={ 7,4,9,8,10,2,3,11,55,23};
            mergesort(a, 0, 9);
            pa(a,"final");
        }

        private  void pa(int[] a, string b)  //通用方法，用于显示数组
        {
            string s = "";
            for (int i = 0; i < a.Length; i++)
            {
                s = s + a[i].ToString()+"、";
            }
            s = s.Substring(0, s.Length - 1);
            MessageBox.Show(b, "q=" + s.ToString(), MessageBoxButtons.OK);
        }

        private void button5_Click(object sender, EventArgs e)  //0-1背包问题的动态规划法，主程序
        {
            int n=5, W=17; //n是物品数量，W是背包能装的总重量
            int[] weights = {2,2,6,5,4};  //物品的重量
            int[] values = {6,3,5,4,6};     //物品的价值
            int []x=new int [n];           //x数组，用0表示不装某物品，1表示装入某物品
            int[,] c = new int[n, W];       //二维数组，相当于创建表格，后续填表
            c = pack(n, W, weights, values);
            int i;
            for (i = n; i > 1; i--)
            {
                if (c[i, W] == c[i - 1, W])
                {
                    x[i - 1] = 0;
                }
                else
                {
                    x[i - 1] = 1;
                    W = W - weights[i - 1];
                }
            }
            if (c[1, W] == 0)
            {
                x[0] = 0;
            }
            else
            {
                x[0] = 1;
            }
            pa(x, "背包");  //显示结果

        }
        private int[,] pack(int n, int W, int[] weights, int[] value)  //填表
        {
            int i, w;
            int [ ,] c=new int [n+1,W+1];
            for (w = 0; w <= W; w++) 
            {
                c[0, w] = 0;  //首列都为0
            }
            for (i = 1; i <= n; i++)
            {
                c[i, 0] = 0;   //首行都为0
                for (w = 1; w <= W; w++) //逐行填写
                {
                    if (weights[i - 1] <= w)  //如果背包剩余重量大于物品重量
                    {
                        if (value[i - 1] + c[i - 1, w - weights[i - 1]] > c[i - 1, w])
                        {
                            c[i, w] = value[i - 1] + c[i - 1, w - weights[i - 1]];  //放入第i-1个物品
                        }
                        else
                        {
                            c[i, w] = c[i - 1, w];  //不放入第i-1个物品
                        }
                    }
                    else
                    {
                        c[i, w] = c[i - 1, w];  //不放入第i-1个物品
                    }
                }
            }
            return c;
        }

        private void button6_Click(object sender, EventArgs e)  //动态规划法最长公共子串问题
        {
            string[] x = { "A", "B", "C", "B", "D", "A","B"};
            string[] y = { "B", "D", "C", "A", "B", "A"};
            int j = x.Length;
            int i = y.Length;
            string [,] L=new string[i+1,j+1];
            int[,] B = new int[i + 1, j + 1];
            string[,] C = new string[i + 1, j + 1];
            B[0, 0] = 0;
            C[0, 0] = "※0";
            L[0, 0] = "※";
            for (int ii = 1; ii <= i; ii++)
            {
                B[ii, 0] = 0;
                L[ii, 0] = "※";
                C[ii, 0] = "※0"+y[ii-1];
                for (int jj = 1; jj <= j; jj++)
                {
                    B[0, jj] = 0;
                    C[0, jj] = "※"+x[jj-1];
                    L[0, jj] = "※";
                    if (y[ii-1] == x[jj-1])
                    {
                        B[ii, jj] = B[ii - 1, jj - 1] + 1;
                        L[ii, jj] = "♂";
                        C[ii, jj] = "♂" + B[ii, jj].ToString();
                    }
                    else
                    {
                        if (B[ii - 1, jj] >= B[ii, jj - 1])
                        {
                            B[ii, jj] = B[ii - 1, jj];
                            L[ii, jj] = "↑";
                            C[ii, jj] = "↑" + B[ii, jj].ToString();
                        }
                        else
                        {
                            B[ii, jj] = B[ii, jj-1];
                            L[ii, jj] = "←";
                            C[ii, jj] = "←" + B[ii, jj].ToString();
                        }
                    }
                }
            }

            int len=B[i, j];
            for (int f = 0; f <= j; f++)
            {

            }

            toDatagrid(C);
           
        }

        private void toDatagrid(string [,] C)  //通用函数，输出字符数组到datagridview
        {
            DataTable dt = new DataTable();

            for (int kk = 0; kk < C.GetLength(1); kk++)
                dt.Columns.Add(kk.ToString(), typeof(string));

            for (int p = 0; p < C.GetLength(0); p++)
            {
                DataRow dr = dt.NewRow();
                for (int k = 0; k < C.GetLength(1); k++)
                    dr[k] = C[p, k];
                dt.Rows.Add(dr);
            }
            dataGridView1.DataSource = dt;
        }

        private void toDatagrid2(int[,] C)  //通用函数，输出二维整数数组到datagridview
        {
            DataTable dt = new DataTable();

            for (int k = 0; k < C.GetLength(1); k++)
                dt.Columns.Add(k.ToString(), typeof(string));

            for (int p = 0; p < C.GetLength(0); p++)
            {
                DataRow dr = dt.NewRow();
                for (int k = 0; k < C.GetLength(1); k++)
                    dr[k] = C[p,k].ToString();
                dt.Rows.Add(dr);
            }
            dataGridView1.DataSource = dt;
        }

        private void toDatagrid3(double[,] C)  //通用函数，输出双精度数数组到datagridview
        {
            DataTable dt = new DataTable();

            for (int k = 0; k < C.GetLength(1); k++)
                dt.Columns.Add(k.ToString(), typeof(string));

            for (int p = 0; p < C.GetLength(0); p++)
            {
                DataRow dr = dt.NewRow();
                for (int k = 0; k < C.GetLength(1); k++)
                    dr[k] = C[p, k].ToString();
                dt.Rows.Add(dr);
            }
            dataGridView1.DataSource = dt;
        }

        private void toGrid(int [] a)   //通用函数，输出一维整数数组到datagridview
        {
            DataTable dt = new DataTable();
            for (int kk = 0; kk < a.Length; kk++)
                dt.Columns.Add(kk.ToString(), typeof(string));
            for (int i = 0; i < a.Length; i++)
            {
                DataRow dr = dt.NewRow();
                    dr[i] = a[i];
                dt.Rows.Add(dr);
            }
            dataGridView1.DataSource = dt;
        }

        private void button7_Click(object sender, EventArgs e) //回溯法背包问题主方法
        {
            float[] values = {11,21,31,33,43,53,55,65}; //物品的价值数值：已按单位价值排序
            int[] weights = {1,11,21,23,33,43,45,55};  //物品的重量：已按单位价值排序
            float[] VW=new float [values.Length];  //物品单位重量价值：价值/重量，已从大到小排序
            int W = 110;  //背包总容量
            for (int i = 0; i < values.Length; i++)
            {
                VW[i] = values[i] / weights[i];   //物品单位重量价值：价值/重量，已从大到小排序
            }

            int current_weight = 0;  //当前背包重量
            float current_profit = 0;  //当前背包价值
            int weight = 0;           //背包初始重量
            float profit = -1;         //背包初始价值
            int index = 0;
            int[] X = new int[values.Length];
            int[] Y = new int[values.Length];

            while (true)
            {
                while (index < values.Length && current_weight + weights[index] <= W)  //深度优先，装到不能再装为止
                {
                    current_profit += values[index];
                    current_weight += weights[index];
                    Y[index] = 1;
                    index++;
                }
                if (index >= values.Length-1)  //如果已经到达叶子结点
                {
                    weight = current_weight;
                    profit = current_profit;
                    index = values.Length-1;
                    for (int k = 0; k < values.Length; k++)  //Y数组就是一个可行解
                    {
                        X[k] = Y[k];
                    }
                }
                else
                {
                    Y[index] = 0;  //背包已装满，后续结点不再装
                }

                while (Bound(values, weights, VW, W, current_profit, current_weight, index) <= profit)  //可获得最大值小于现值时，回溯
                {
                    while (index != 0  && Y[index] != 1)  //回溯到上一个选中的节点
                    {
                        index--;
                    }
                    if (index == 0)  //如果已回溯到根节点，结束所有循环
                    {
                        toGrid(X);  //将数组X作为结果输出
                        return;
                    }
                    Y[index] = 0;  //将该节点设为不选
                    current_profit -= values[index];  //减去相应价值
                    current_weight -= weights[index]; //减去相应重量
                }
                index++;
            }
            
        }

        private float Bound(float[] values, int[] weights, float[] VW, int W, float profit_gained, int weight_used, int k)  //当前背包余量下，可获得的最大价值
        {
            for (int i = k + 1; i < weights.Length; i++)  //搜索可行解
            {
                if (weight_used + weights[i] <= W)
                {
                    profit_gained += values[i];
                    weight_used += weights[i];
                }
                else
                {
                    profit_gained += VW[i] * (W - weight_used);
                    weight_used = W;
                    return profit_gained;
                }
            }
            return profit_gained;
        }

        private void button8_Click(object sender, EventArgs e)  //回溯法n皇后问题
        {
            int n=8;  //4X4方格
            int [] Column_Num=new int [n+1];   //一维数组的序号代表行，值代表列
            int index = 1; //代表行
            int answer_num=0;
            for (int i = 1; i <= n; i++)
            {
                Column_Num[i] = 0; //赋初值
            }
            toGrid(Column_Num);
            while (index > 0)
            {
                Column_Num[index]++;  //从第1列开始，如果回溯则在上一次的列的基础上尝试下一列
                while (Column_Num[index] <= n && Place(Column_Num, index,n)==0)  //为0表示不可行
                {
                    Column_Num[index]++;  //如果不可行移至下一列再试,Column_Num[index]的值可能超过n
                }
                if (Column_Num[index] <= n)  //已放至最后一列
                {                  
                    if (index == n)  //放置最后一个皇后成功
                    {
                        answer_num++;
                        MessageBox.Show("完成", "完成");
                        toGrid(Column_Num);
                        return;
                    }
                    else
                    {
                        index++;  //查找下一行
                        Column_Num[index] = 0;
                    }
                }
                else
                {
                    index--;  //无法放置，回溯上一行
                    
                }
            }
            
        }

        private int Place(int [] Column,int index,int n)   //检查所放的皇后位置可不可行
        {
            int i; //代表行
            for(i=1;i<index;i++)  //遍历第index行之前的所有行
            {
                int Column_differ=System.Math.Abs(Column[index]-Column[i]);  //列的差
                int Row_differ=System.Math.Abs(index-i);  //行的差
                if(Column[i]==Column[index] || Column_differ==Row_differ || Column[i]>n)   //行的差/列的差等于1时，表示斜线上不可行
                {
                    return 0;  //不可行
                }
            }
            return 1; //可行
        }

        private void button9_Click(object sender, EventArgs e)   //矩阵链乘问题，主方法
        {
            int[] p = { 3, 4, 30, 5, 16, 20, 25 };  //矩阵的p数组，代表A1矩阵为3X4、A2矩阵为4X30……
            int[,] m = new int[8,8];
            int[,] s = new int[8,8];
            for (int i = 0; i < 8; i++)
            {
                m[i,0] = i;
                s[i, 0] = i;
                for (int j = 1; j < 8; j++)
                {
                    m[i,j] = 0;
                    s[i,j] = 0;
                }
            }
           MatrixChain(p, m, s);
            toDatagrid2(s);
            result(s,1,6);
        }
        void MatrixChain(int[] p, int[,] m, int[,] s)  //矩阵链乘问题
        {
            int N=6;  //总共N个矩阵，矩阵个数比p数组的长度少1
            int i, j, k, t;
            for ( i = 0; i <= N; i++)
            {
                m[i,i] = 0;
            }

            for ( t = 2; t <= N; t++)  //链乘矩阵的个数，至少为2，最多为N个
            {
                for ( i = 1; i <= N - t+1; i++)  //t个矩阵相乘，从下标为1的矩阵开始，找t个相连的矩阵
                {
                    j = i + t -1;     // 共t个矩阵相乘，超始下标是i，终止下标就是i+t-1
                    m[i,j] = 1000000;  // 设置一个最大代价
                    for (k = i; k < j; k++)
                    {
                        int temp = m[i,k] + m[k + 1,j] + p[i - 1] * p[k] * p[j];
                        if (temp < m[i,j])
                        {
                            m[i,j] = temp;
                            s[i,j] = k;
                        }
                    }
                }
            }
        }

        void result(int[,] s, int i, int j)  //矩阵链乘问题结果显示
        {
            
            if (i == j)
            {
                label7.Text = label7.Text + "A" + i.ToString();
            }
            else
            {
                label7.Text = label7.Text + "(";
                result(s, i, s[i, j]);
                result(s, s[i, j] + 1, j);
                label7.Text = label7.Text + ")";
            }
            
        }

        private void button10_Click(object sender, EventArgs e)   //堆排序，主方法
        {
            int[] data = {55,60,40,10,80,65,15,5,75};
            int n = data.Length;
            for (int i =0 ; i <= n / 2 - 1; i++)
            {
                HeapAdjust(data, i, n - 1);
            }
            HeapAdjust(data, 0, n - 1);
            pa(data, "大根");  //显示
        }
        private void HeapAdjust(int [] data, int s, int m)  //堆排序，组建大根堆
        {
            int tmp, j;
            tmp = data[s];
            for (j = 2 * s + 1; j <= m; j = j * 2 + 1)
            {
                if (j < m && data[j] < data[j + 1])
                {
                    j++;
                }
                if (tmp > data[j])
                {
                    break;
                }
                data[s] = data[j];
                s = j;
            }
            data[s] = tmp;
        }

        private void button11_Click(object sender, EventArgs e)  //n凸多边形的切割问题
        {
            int n = 6;  //多边形的边数
            double[,] t=new double [n,n];  //t[i,j]表示从i-1点开始至j点构成的多边形的最优权值
            int[,] s = new int[n, n];  //s[i,j]=k，表示由点i-1,j,k这三个点构成一个三角形
            for (int i = 1; i < n; i++)
            {
                t[i, i] = 0;
            }
            for (int r = 2; r <= n; r++)  //问题规模，如t[i,j]时，j和i相隔r条边；最大可选r=n，相当于终点与起点重合
            {
                for (int i = 1; i < n - r+1; i++)
                {
                    int j = i + r - 1;  //距离i点最远的点的编号，当r=n时最大取值为n-1
                    
                    t[i, j] = t[i + 1, j] + weight(i - 1, i, j);
                    s[i, j] = i;
                    for (int k = i + 1; k < j; k++)
                    {
                        double temp = t[i, k] + t[k + 1, j] + weight(i - 1, k, j);
                        if (temp < t[i, j])
                        {
                            t[i, j] = temp;
                            s[i, j] = k;
                        }
                    }
                }
            }
            toDatagrid2(s);     //输出最佳方案切割位置点
            //toDatagrid3(t);  //输出最终权值
        }
        private double weight(int i, int j, int k) //求权值
        {
            double[,] w = {{0,5,8.1,9.2,9.8,10},
                            {5,0,3.2,4.5,5.7,6.7},
                            {8.1,3.2,0,1.4,3.2,5},
                            {9.2,4.5,1.4,0,2,4.1},
                            {9.8,5.7,3.2,2,0,2.2},
                            {10,6.7,5,4.1,2.2,0}};
            if (k == 6) k = 0;    //数组从0到5编号，因此多边形的第6个点与第0点重合
            return w[i, j] + w[j, k] + w[i, k];
        }

        private void button12_Click(object sender, EventArgs e)  //递归回溯法：在方阵里填数，使相邻数相加为质数
        {
            //初始化数据
            
            int[,] a = new int[3, 3];  //数组，用于存放方阵里的数
            bool[] vis = new bool[N+1];  //标志用于记录1到10这十个数是否已经被使用
            for (int i = 0; i <= N; i++)
            {
                vis[i] = false;
            }
              
            List<int> list = new List<int>();  //list用于记录所有结果
            dfs(a, 0, 0, vis, list);

            //输出得到的结果list
            string s="";
            for (int i = 0; i < list.Count; i++)
            {
                s += list[i].ToString()+"、";
                if ((i + 1) % 9 == 0) { s = s.Substring(0, s.Length - 1) + "\n"; }
            }
            MessageBox.Show((list.Count/9).ToString(), "总共数量", MessageBoxButtons.OK, MessageBoxIcon.Information);
            MessageBox.Show(s, "", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        private bool isprime(int n)  //判断一个整数是不是质数
        {
            for (int i = 2; i * i <= n; i++)
            {
                if (n % i == 0) return false;
            }
            return true;
        }
        private bool check(int [,]a,int x, int y, int k)  //检查k跟它的上、左位置的数相加是否为质数
        {
            if (y>0 && !isprime(a[x, y - 1] + k)) return false;  //与左侧数相加不是质数
            if (x>0 && !isprime(a[x - 1, y] + k)) return false;  //与上方数相加不是质数
            return true;
        }
        private void dfs(int[,] a, int x, int y, bool[] vis, List<int> list)
        {
            if (x == 3)  //x=3说明遍历完成，开始输出数组
            {
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        list.Add(a[i,j]);
                    }
                }
                return;
            }
            for (int i = 1; i <= N; i++)
            {
                if (!vis[i] && check(a, x, y, i))
                {
                    a[x, y] = i;
                    vis[i] = true;
                    if (y == 2) dfs(a, x + 1, 0, vis,list);
                    else dfs(a, x, y + 1, vis,list);
                    a[x, y] = 0;   //回溯
                    vis[i] = false;    //回溯               
                }
            }
        }

        private void button13_Click(object sender, EventArgs e)  //非递归回溯：在方阵里填数，使相邻数相加为质数
        {
            for (int i = 1; i <= N; i++)
            {
                b[i] = 1;  //设置初值
            }
            List<int> list = new List<int>();
            find(list);
            MessageBox.Show((list.Count/10).ToString(), "结果组数", MessageBoxButtons.OK); //结果组数
            string s = "";
            for (int i = 0; i < list.Count; i++)
            {
                s += list[i].ToString() + "、";
            }
            MessageBox.Show(s, "所有结果", MessageBoxButtons.OK);
        }

        private void write(int[] a, List<int> list)   //将数组a转为list
        {
           // List<int> list = new List<int>();
            for (int i = 0; i < a.Length; i++)
            {
                list.Add(a[i]);
            }
            string s = "";
            for (int i = 0; i < list.Count; i++)
            {
                s += list[i].ToString() + "、";
            }
           // MessageBox.Show((list.Count/10).ToString(), "结果", MessageBoxButtons.OK);
        }

        private int selectNum(int start)   //选择下一个要试探填写的数，返回0表示该数已被选择
        {
            int j;
            for (j = start; j <= N; j++)
            {
                if (b[j]==1) return j;
            }
            return 0;
        }

        private int check(int pos)  //检测当前位置放入的数是否合理
        {
            int i, j;
            if (pos < 0) return 0;
            for (i = 0; (j = checkMatrix[pos,i]) >= 0; i++)
            {
                if (!isprime(a[pos] + a[j]))    //i是表示checkMatrix矩阵中pos行第i个数（现总共为3个），j就是该数的实际值，即需要对比的位置
                {
                    return 0;
                }
            }
            return 1;
        }

        private int extend(int pos)  //扩展至下一位置
        {
            a[++pos] = selectNum(1);  //a[pos]即选中的数，因此要把b[a[pos]]置0，表示该数已被选用
            b[a[pos]] = 0;
            return pos;  //返回下一个位置
        }
        private int change(int pos)   //改变位置，即回溯至前面的位置
        {
            int j = selectNum(a[pos] + 1);
            while (pos >= 0 && (j = selectNum(a[pos] + 1)) == 0)  //j==0说明所选的数不可用,返回上一个位置pos-1位置
            {
                b[a[pos--]] = 1;
            }
            if (pos < 0) return -1;
            b[a[pos]] = 1;
            a[pos] = j;
            b[j] = 0;
            return pos;
        }
        private void find(List<int> list)  //遍历寻找可行解
        {
            int ok = 1, pos = 0;
            a[pos] = 1; b[a[pos]] = 0;           
            do
            {
                if (ok == 1)
                {
                    if (pos == 8)
                    {
                        //MessageBox.Show("得到一个解", "结果", MessageBoxButtons.OK);
                        write(a,list);
                        pos = change(pos);
                    }
                    else
                    {
                        pos = extend(pos);  //往下扩展
                    }
                }
                else
                {                   
                    pos = change(pos);  //如果ok==0，说明所选的数不可行，需要回溯                   
                }
                ok = check(pos);  //检查该数是否符合要求，如果不符合要求则ok=0
            } while (pos > 0);
        }

        private void button14_Click(object sender, EventArgs e)  //分治法：比赛日程的安排问题
        {
            int k = 4;  //规模，即有2^k个比赛选手
            int N=(int)(Math.Pow(2,k)+1);  //2的k次方加1
            int[,] a = new int[N, N-1];  //用于存放结果，行代表选手编号，列代表比赛日
            int twoml, twom, i, j, m;
            m = 1;
            twoml = 1;
            a[1, 1] = 2;
            a[2, 1] = 1;  //预设两位选手的比赛日程
            while (m < k)
            {
                m++;    //分治规模，从小到大，m的最大值为k
                twoml += twoml;  //twoml的值随着m的扩大，依次从2、4、8、16……2^(k-1)，等于规模数（选手总数）的一半
                twom = 2 * twoml;   //twom的值为4、8、16……2^k，等于规模数（选手总数）
                /*以下填写左下角*/
                for (i = twoml + 1; i <= twom; i++)   //填写左下角，i的值从选手编号的后半第1个数开始
                {
                    
                    for (j = 1; j <= twoml - 1; j++)   //j的值，即列值（比赛日），从1到规模数一半减1
                    {
                        
                        a[i,j] = a[i - twoml,j] + twoml;  //等于上半对应的值加上规模数的一半
                    }
                }
                /*以下填写右上角*/
                a[1,twoml] = twoml + 1;  //填写日程表右上角第一列第1个数，即规模数后半的第1个数
                for (i = 2; i <= twoml; i++)
                {
                    a[i,twoml] = a[i - 1, twoml] + 1;   //右上角第一列，第i行等于其上方数加1
                }

                for (j = twoml + 1; j < twom; j++)   //右上角第2列(twoml+1)至最后一列(twom-1)
                {
                    for (i = 1; i < twoml; i++)    //右上角第1行至第twoml-1行
                    {
                        a[i, j] = a[i + 1, j - 1];   //等于左侧一列左下方的选手编号
                    }
                    a[twoml, j] = a[1, j - 1];   //右上角每列的最后一行的值等于前一列第一个值
                }
                /*以下填写右下角*/
                for (j = twoml; j < twom; j++)  //j为列编号，从规模数一半开始
                {
                    for (i = 1; i <= twoml; i++)  //i为选手编号，右下角只填写前一半选手编号
                    {
                        a[a[i, j], j] = i;  //a[i,j]代表右上角同一列上第i行的数，按照同列上的第一行的数对应的行开始填数1、2、3……
                    }
                }              
            }
            toDatagrid2(a);
        }

        private void button15_Click(object sender, EventArgs e)  //贪心法多机调度问题
        {
            int[] s = { 16, 14, 6, 5, 4, 3,2 };  //各任务耗时，按从长到短排序
            int n = s.Length;   //任务总数量
            int m = 3;          //机器数量，小于n
            int [] d=new int [m];  //m台机器的时间数组
            for (int i = 0; i < m; i++)
            {
                d[i] = s[i];    //初始赋值，先选前面最大三个数
            }
            for (int i = m; i < n; i++)
            {
                d[min(d)] += s[i];  //把任务分配给d数组中值最小的数
            }

            pa(d, "结果");
        }

        private int min(int[] a)  //返回数组中最小数对应的下标
        {
            int t = 0;
            for (int i = 1; i < a.Length; i++)
            {
                if (a[t] > a[i])
                {
                    t = i;
                }
            }
            return t;
        }

        private void button1_Click(object sender, EventArgs e)  //马的遍历问题，主函数
        {
            int sx, sy, i, j, step=0, no, start;
            List <int [,]> list=new List<int[,]>();
            
            for (sx = 0; sx < 8; sx++)
            {
                for (sy = 0; sy < 8; sy++)
                {
                    start = 0;
                    do
                    {
                        for (i = 0; i < 8; i++)
                        {
                            for (j = 0; j < 8; j++)
                            {
                                board[i, j] = 0;   //清棋盘，全部置0
                            }
                        }
                        i = sx;
                        j = sy;
                        for (step = 1; step <= 64; step++)  //step代表第几步，第1步为起始位置
                        {
                            if ((no = next(i, j, start)) == -1) break;  //无出口，结束循环,no是下一步最少出口的着数
                            i += deltai[no];
                            j += deltaj[no];
                            board[i, j] = step;
                        }
                        if (step > 64)   //找到一个可行解
                        {
                        //将可行解转移到kf，然后绑定到list；不能直接用list.Add(board)，因为后面的数组会覆盖前面的数组
                            int[,] kf = new int [8,8];        
                            for (int ii = 0; ii < 8; ii++)
                            {
                                for (int jj = 0; jj < 8; jj++)
                                {
                                    kf[ii,jj] = board[ii,jj];
                                }
                            }                           
                            list.Add(kf);
                            break; 
                        }
                        start++;
                    } while (step <= 64);
                }
            }
            for (int ff = 0; ff < list.Count; ff++)  //逐个显示可行解，一共64个
            {
                MessageBox.Show(ff.ToString(), "序号", MessageBoxButtons.OK);
                toDatagrid2(list[ff]);
            }
        }

        private int exitn(int i, int j, int s, int[] a)  //求(i,j)的出口数，s为着数
        {
            int i1, j1, k, count;
            for (count = k = 0; k < 8; k++)
            {
                i1 = i + deltai[k];
                j1 = j + deltaj[k];
                if (i1 >= 0 && i1 < 8 && j1 >= 0 && j1 < 8 && board[i1, j1] == 0)  //下一着的位置须符合不出界、且是马尚未走过的位置
                {
                    a[count++] = k;
                }
            }
            return count;
        }
        private int next(int i, int j, int s)    //选下一出口,即求出坐标为(i,j)、起始着数为s的下一出口数量最少的着数
        {
            int m, k, kk=0, min, temp;
            int[] a = new int[8];
            int[] b = new int[8];
            m = exitn(i, j, s, a);   //坐标为(i,j)，着数为s，的马的出口数量, a存放着可行着数
            if (m == 0) return -1;   //无出口，返回-1
            for (min = 9, k = 0; k < m; k++)  //寻找可行着数中，下一出口最小的着数
            {
                temp = exitn(i + deltai[a[k]], j + deltaj[a[k]], s, b);
                if (temp < min)
                {
                    min = temp;
                    kk = a[k];
                }
            }
            return kk;
        }

        private void button16_Click(object sender, EventArgs e)   //贪心法装箱问题
        {
            int[] ele = {60,45,35,20,20,20 };  //物品体积
            int [] box=new int [ele.Length];   //准备箱子
            string[] list = new string[ele.Length];
            string s = "";
            int boxcount = 0;
            for (int i = 0; i < ele.Length; i++)
            {
                box[i] = 100;   //每个箱子容量为100
            }
            for (int i = 0; i < ele.Length; i++)
            {
                for (int j = 0; j < box.Length; j++)
                {
                    if (ele[i] < box[j])
                    {
                        box[j] -= ele[i];   //放入箱子
                        list[j] += (i+1).ToString() + "、";  //记录每个箱子装哪些物品，物品编号从1开始
                        break;
                    }
                }
            }
            for (int i = 0; i < ele.Length; i++)  //显示结果
            {
                if (list[i] != null)
                {
                    s += list[i].Substring(0,list[i].Length-1) + "；";
                    boxcount++;
                }
            }
            MessageBox.Show(boxcount.ToString(), "使用的箱子数量", MessageBoxButtons.OK);
            MessageBox.Show(s, "每个箱子装入的物品编号", MessageBoxButtons.OK);
        }

        
    }
}
